สำรวจพลังของ Frontend Monorepo ด้วย Lerna และ Nx เรียนรู้การจัดการ Workspaces, การแชร์โค้ด และการ build ที่มีประสิทธิภาพสำหรับโปรเจกต์ขนาดใหญ่
Frontend Monorepo: การจัดการ Workspaces ด้วย Lerna และ Nx
ในภูมิทัศน์ของการพัฒนา Frontend ที่มีการเปลี่ยนแปลงอยู่เสมอ การจัดการโปรเจกต์ขนาดใหญ่และซับซ้อนอาจเป็นความท้าทายที่สำคัญ การตั้งค่าแบบ multi-repo แบบดั้งเดิม แม้ว่าจะให้ความเป็นอิสระ แต่ก็อาจนำไปสู่การซ้ำซ้อนของโค้ด ปัญหาในการจัดการ dependencies และเครื่องมือที่ไม่สอดคล้องกัน นี่คือจุดที่สถาปัตยกรรม monorepo โดดเด่นขึ้นมา Monorepo คือ repository เดียวที่มีหลายโปรเจกต์ ซึ่งมักจะเกี่ยวข้องกัน และถูก build และ versioned ร่วมกัน แนวทางนี้มีข้อได้เปรียบมากมาย แต่การจัดการ monorepo อย่างมีประสิทธิภาพนั้นต้องการเครื่องมือเฉพาะทาง บทความนี้จะสำรวจโซลูชันยอดนิยมสองอย่าง: Lerna และ Nx
Monorepo คืออะไร?
Monorepo คือ repository ระบบควบคุมเวอร์ชันที่เก็บโค้ดสำหรับหลายโปรเจกต์ โปรเจกต์เหล่านี้อาจเกี่ยวข้องกันหรือไม่เกี่ยวข้องกันเลย สิ่งสำคัญคือทั้งหมดอยู่ใน repository เดียวกัน บริษัทอย่าง Google, Facebook, Microsoft และ Uber ได้นำ monorepos มาใช้อย่างประสบความสำเร็จในการจัดการฐานโค้ดขนาดมหึมาของตน ลองนึกภาพ Google ที่เก็บโค้ดเกือบทั้งหมด รวมถึง Android, Chrome และ Gmail ไว้ใน repository เดียว
ข้อดีของ Monorepo
- การแชร์และนำโค้ดกลับมาใช้ใหม่: แชร์โค้ดระหว่างโปรเจกต์ได้ง่ายโดยไม่ต้องใช้เวิร์กโฟลว์การแพ็กเกจและการเผยแพรที่ซับซ้อน ลองนึกถึงไลบรารีระบบออกแบบที่สามารถรวมเข้ากับแอปพลิเคชันหลายตัวภายใน repository เดียวกันได้อย่างราบรื่น
- การจัดการ Dependencies ที่ง่ายขึ้น: จัดการ dependencies ในที่เดียว ทำให้มั่นใจได้ถึงความสอดคล้องในทุกโปรเจกต์ การอัปเดต dependency ของไลบรารีที่แชร์ จะอัปเดตโปรเจกต์ทั้งหมดที่ต้องพึ่งพามันโดยอัตโนมัติ
- การเปลี่ยนแปลงแบบ Atomic: ทำการเปลี่ยนแปลงที่ครอบคลุมหลายโปรเจกต์ในการ commit ครั้งเดียว เพื่อให้มั่นใจในความสอดคล้องและลดความซับซ้อนในการทดสอบ ตัวอย่างเช่น การ refactor ที่ส่งผลต่อทั้ง frontend และ backend สามารถทำได้แบบ atomic
- การทำงานร่วมกันที่ดีขึ้น: ทีมสามารถทำงานร่วมกันในโปรเจกต์ต่างๆ ภายใน repository เดียวกันได้อย่างง่ายดาย ส่งเสริมการแบ่งปันความรู้และการพัฒนาข้ามสายงาน นักพัฒนาสามารถเรียกดูและทำความเข้าใจโค้ดข้ามทีมต่างๆ ได้ง่าย
- เครื่องมือและแนวปฏิบัติที่สอดคล้องกัน: บังคับใช้มาตรฐานการเขียนโค้ด กฎ linting และกระบวนการ build ที่สอดคล้องกันในทุกโปรเจกต์ สิ่งนี้ช่วยปรับปรุงคุณภาพโค้ดและความสามารถในการบำรุงรักษา
- การ Refactoring ที่ง่ายขึ้น: โปรเจกต์ refactoring ขนาดใหญ่จะง่ายขึ้น เนื่องจากโค้ดที่เกี่ยวข้องทั้งหมดอยู่ใน repository เดียวกัน สามารถใช้เครื่องมือ refactoring อัตโนมัติได้ทั่วทั้งฐานโค้ด
ความท้าทายของ Monorepo
- ขนาด Repository: Monorepos อาจมีขนาดใหญ่มาก ซึ่งอาจทำให้การ clone และ indexing ช้าลง เครื่องมือเช่น `git sparse-checkout` และ `partial clone` สามารถช่วยลดปัญหานี้ได้
- เวลาในการ Build: การ build monorepo ทั้งหมดอาจใช้เวลานาน โดยเฉพาะอย่างยิ่งสำหรับโปรเจกต์ขนาดใหญ่ เครื่องมือเช่น Lerna และ Nx มีกระบวนการ build ที่ปรับให้เหมาะสมเพื่อแก้ไขปัญหานี้
- การควบคุมการเข้าถึง: การจำกัดการเข้าถึงส่วนเฉพาะของ monorepo อาจซับซ้อน จำเป็นต้องมีการวางแผนและการดำเนินการกลไกการควบคุมการเข้าถึงอย่างรอบคอบ
- ความซับซ้อนของเครื่องมือ: การตั้งค่าและจัดการ monorepo ต้องการเครื่องมือและความรู้เฉพาะทาง เส้นโค้งการเรียนรู้ (learning curve) อาจสูงชันในช่วงแรก
Lerna: การจัดการโปรเจกต์ JavaScript ใน Monorepo
Lerna เป็นเครื่องมือยอดนิยมสำหรับการจัดการโปรเจกต์ JavaScript ใน monorepo มันช่วยเพิ่มประสิทธิภาพเวิร์กโฟลว์ในการจัดการ repository แบบ multi-package ด้วย Git และ npm เหมาะอย่างยิ่งสำหรับโปรเจกต์ที่ใช้ npm หรือ Yarn สำหรับการจัดการ dependencies
คุณสมบัติหลักของ Lerna
- การจัดการเวอร์ชัน: Lerna สามารถจัดการเวอร์ชันและเผยแพร่แพ็กเกจโดยอัตโนมัติตามการเปลี่ยนแปลงที่เกิดขึ้นตั้งแต่การ release ล่าสุด มันใช้ conventional commits เพื่อกำหนดหมายเลขเวอร์ชันถัดไป
- การจัดการ Dependencies: Lerna จัดการ dependencies ระหว่างแพ็กเกจ ทำให้มั่นใจได้ว่าแพ็กเกจภายใน monorepo สามารถพึ่งพาซึ่งกันและกันได้ มันใช้ symlinking เพื่อสร้าง dependencies ในเครื่อง
- การดำเนินการ Task: Lerna สามารถดำเนินการคำสั่งข้ามหลายแพ็กเกจแบบขนาน ทำให้กระบวนการ build และทดสอบเร็วขึ้น รองรับการรันสคริปต์ที่กำหนดไว้ใน `package.json`
- การตรวจจับการเปลี่ยนแปลง: Lerna สามารถตรวจจับว่าแพ็กเกจใดเปลี่ยนแปลงไปตั้งแต่การ release ล่าสุด ทำให้สามารถ build และ deploy แบบกำหนดเป้าหมายได้
ตัวอย่างการใช้งาน Lerna
เราจะแสดงตัวอย่างการใช้งาน Lerna ด้วยตัวอย่างที่ง่ายขึ้น สมมติว่าเรามี monorepo ที่มีสองแพ็กเกจ: `package-a` และ `package-b` `package-b` ต้องพึ่งพา `package-a`
monorepo/
├── lerna.json
├── package.json
├── packages/
│ ├── package-a/
│ │ ├── package.json
│ │ └── index.js
│ └── package-b/
│ ├── package.json
│ └── index.js
1. การเริ่มต้น Lerna:
lerna init
สิ่งนี้จะสร้าง `lerna.json` และอัปเดต `package.json` ระดับรูท ไฟล์ `lerna.json` จะกำหนดค่าพฤติกรรมของ Lerna
2. การติดตั้ง Dependencies:
npm install
# หรือ
yarn install
สิ่งนี้จะติดตั้ง dependencies สำหรับทุกแพ็กเกจใน monorepo ตามไฟล์ `package.json` ในแต่ละแพ็กเกจ
3. การรันคำสั่งข้ามแพ็กเกจ:
lerna run test
สิ่งนี้จะรันสคริปต์ `test` ที่กำหนดไว้ในไฟล์ `package.json` ของทุกแพ็กเกจที่มีสคริปต์นี้
4. การเผยแพร่แพ็กเกจ:
lerna publish
คำสั่งนี้จะวิเคราะห์ประวัติ commit กำหนดว่าแพ็กเกจใดเปลี่ยนแปลงไป เพิ่มเวอร์ชันของมันตาม conventional commits และเผยแพร่ไปยัง npm (หรือ registry ที่คุณเลือก)
การกำหนดค่า Lerna
ไฟล์ `lerna.json` เป็นหัวใจสำคัญของการกำหนดค่า Lerna ช่วยให้คุณปรับแต่งพฤติกรรมของ Lerna ได้ เช่น:
- `packages`: ระบุตำแหน่งของแพ็กเกจภายใน monorepo มักจะตั้งค่าเป็น `["packages/*"]`
- `version`: ระบุกรรมวิธี versioning สามารถเป็น `independent` (แต่ละแพ็กเกจมีเวอร์ชันของตัวเอง) หรือเวอร์ชันคงที่
- `command`: อนุญาตให้คุณกำหนดค่าตัวเลือกสำหรับคำสั่ง Lerna เฉพาะ เช่น `publish` และ `run`
ตัวอย่าง `lerna.json`:
{
"packages": [
"packages/*"
],
"version": "independent",
"npmClient": "npm",
"useWorkspaces": true,
"command": {
"publish": {
"conventionalCommits": true,
"message": "chore(release): publish"
}
}
}
Nx: ระบบ Build ที่ชาญฉลาด รวดเร็ว และขยายได้
Nx เป็นระบบ build ที่ทรงพลังที่ให้คุณสมบัติขั้นสูงสำหรับการจัดการ monorepo มันมุ่งเน้นไปที่ incremental builds, computation caching และ task orchestration เพื่อปรับปรุงเวลา build และประสิทธิภาพของนักพัฒนาอย่างมาก ในขณะที่ Lerna มุ่งเน้นไปที่การจัดการแพ็กเกจเป็นหลัก Nx นำเสนอแนวทางที่ครอบคลุมมากขึ้นในการจัดการเวิร์กโฟลว์ monorepo ทั้งหมด รวมถึงการสร้างโค้ด (code generation), linting, testing และ deployment
คุณสมบัติหลักของ Nx
- Incremental Builds: Nx วิเคราะห์กราฟ dependency ของโปรเจกต์ของคุณ และ build เฉพาะโปรเจกต์ที่เปลี่ยนแปลงไปตั้งแต่การ build ล่าสุด สิ่งนี้ช่วยลดเวลา build ได้อย่างมาก
- Computation Caching: Nx ทำการแคชผลลัพธ์ของ tasks เช่น build และ test เพื่อให้สามารถนำกลับมาใช้ใหม่ได้หาก input ไม่เปลี่ยนแปลง สิ่งนี้ช่วยเร่งวงจรการพัฒนาให้เร็วขึ้นไปอีก
- Task Orchestration: Nx มีระบบ task orchestration ที่ทรงพลัง ซึ่งช่วยให้คุณกำหนด pipeline การ build ที่ซับซ้อนและรันได้อย่างมีประสิทธิภาพ
- Code Generation: Nx มีเครื่องมือ code generation ที่สามารถช่วยคุณสร้างโปรเจกต์, component และ module ใหม่ได้อย่างรวดเร็ว โดยปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุดและมาตรฐานที่สอดคล้องกัน
- Plugin Ecosystem: Nx มี plugin ecosystem ที่หลากหลายซึ่งรองรับเทคโนโลยีและ framework ต่างๆ เช่น React, Angular, Node.js, NestJS และอื่นๆ
- การแสดงภาพกราฟ Dependency: Nx สามารถแสดงภาพกราฟ dependency ของ monorepo ของคุณ ช่วยให้คุณเข้าใจความสัมพันธ์ระหว่างโปรเจกต์และระบุปัญหาที่อาจเกิดขึ้น
- Affected Commands: Nx มีคำสั่งสำหรับรัน tasks เฉพาะในโปรเจกต์ที่ได้รับผลกระทบจากการเปลี่ยนแปลงบางอย่าง สิ่งนี้ช่วยให้คุณมุ่งเน้นความพยายามของคุณในส่วนที่ต้องการความสนใจ
ตัวอย่างการใช้งาน Nx
เราจะแสดงตัวอย่างการใช้งาน Nx ด้วยตัวอย่างที่ง่ายขึ้น เราจะสร้าง monorepo ที่มีแอปพลิเคชัน React และไลบรารี Node.js
1. การติดตั้ง Nx CLI ทั่วโลก:
npm install -g create-nx-workspace
2. การสร้าง Nx Workspace ใหม่:
create-nx-workspace my-monorepo --preset=react
cd my-monorepo
สิ่งนี้จะสร้าง Nx workspace ใหม่พร้อมแอปพลิเคชัน React ตัวเลือก `--preset=react` บอกให้ Nx เริ่มต้น workspace ด้วยการกำหนดค่าเฉพาะ React
3. การสร้างไลบรารี:
nx generate @nrwl/node:library my-library
สิ่งนี้จะสร้างไลบรารี Node.js ใหม่ชื่อ `my-library` Nx จะกำหนดค่าไลบรารีและ dependencies ของมันโดยอัตโนมัติ
4. การ Build แอปพลิเคชัน:
nx build my-app
สิ่งนี้จะ build แอปพลิเคชัน React Nx วิเคราะห์กราฟ dependency และ build เฉพาะไฟล์ที่จำเป็น
5. การรัน Test:
nx test my-app
สิ่งนี้จะรัน unit test สำหรับแอปพลิเคชัน React Nx ทำการแคชผลลัพธ์ของ test เพื่อเร่งการรัน test ในครั้งต่อไป
6. การดู Graph Dependency:
nx graph
สิ่งนี้จะเปิดอินเทอร์เฟซเว็บที่แสดงภาพกราฟ dependency ของ monorepo
การกำหนดค่า Nx
Nx ถูกกำหนดค่าผ่านไฟล์ `nx.json` ซึ่งอยู่ในรูทของ workspace ไฟล์นี้จะกำหนดโปรเจกต์ใน workspace dependencies ของโปรเจกต์ และ tasks ที่สามารถดำเนินการบนโปรเจกต์เหล่านั้นได้
ตัวเลือกการกำหนดค่าหลักใน `nx.json` ได้แก่:
- `projects`: กำหนดโปรเจกต์ใน workspace และการกำหนดค่า เช่น root directory และ build targets
- `tasksRunnerOptions`: กำหนดค่า task runner ซึ่งรับผิดชอบในการดำเนินการ tasks และแคชผลลัพธ์
- `affected`: กำหนดค่าว่า Nx กำหนดว่าโปรเจกต์ใดได้รับผลกระทบจากการเปลี่ยนแปลงอย่างไร
ตัวอย่าง `nx.json`:
{
"npmScope": "my-org",
"affected": {
"defaultBase": "main"
},
"implicitDependencies": {
"package.json": {
"dependencies": "*",
"devDependencies": "*"
},
".eslintrc.json": "*"
},
"tasksRunnerOptions": {
"default": {
"runner": "nx-cloud",
"options": {
"cacheableOperations": ["build", "lint", "test", "e2e"],
"accessToken": "...",
"canTrackAnalytics": false,
"showUsageWarnings": false
}
}
},
"targetDefaults": {
"build": {
"dependsOn": ["^build"],
"inputs": ["production", "default"],
"outputs": ["{projectRoot}/dist"]
}
},
"namedInputs": {
"default": [ "{projectRoot}/**/*", "!{projectRoot}/dist/**/*", "!{projectRoot}/tmp/**/*"],
"production": [ "!{projectRoot}/**/*.spec.ts", "!{projectRoot}/**/*.spec.tsx", "!{projectRoot}/**/*.spec.js", "!{projectRoot}/**/*.spec.jsx"]
},
"generators": {
"@nrwl/react": {
"application": {
"style": "css",
"linter": "eslint",
"unitTestRunner": "jest"
},
"library": {
"style": "css",
"linter": "eslint",
"unitTestRunner": "jest"
},
"component": {
"style": "css"
}
},
}
}
Lerna vs. Nx: เลือกอะไรดี?
ทั้ง Lerna และ Nx เป็นเครื่องมือที่ยอดเยี่ยมสำหรับการจัดการ frontend monorepos แต่ทั้งสองตัวรองรับความต้องการที่แตกต่างกันเล็กน้อย นี่คือการเปรียบเทียบเพื่อช่วยคุณเลือกเครื่องมือที่เหมาะสมสำหรับโปรเจกต์ของคุณ:
| คุณสมบัติ | Lerna | Nx |
|---|---|---|
| จุดเน้น | การจัดการแพ็กเกจ | ระบบ Build และ Task Orchestration |
| Incremental Builds | จำกัด (ต้องการเครื่องมือภายนอก) | มีในตัวและปรับให้เหมาะสมอย่างยิ่ง |
| Computation Caching | ไม่ | ใช่ |
| Code Generation | ไม่ | ใช่ |
| Plugin Ecosystem | จำกัด | กว้างขวาง |
| Learning Curve | ต่ำกว่า | สูงกว่า |
| ความซับซ้อน | ง่ายกว่า | ซับซ้อนกว่า |
| กรณีใช้งาน | โปรเจกต์ที่มุ่งเน้นการจัดการและเผยแพร่ npm packages เป็นหลัก | โปรเจกต์ขนาดใหญ่และซับซ้อนที่ต้องการเวลา build ที่ปรับให้เหมาะสม, code generation และระบบ build ที่ครอบคลุม |
เลือก Lerna หาก:
- คุณต้องการจัดการและเผยแพร่ npm packages เป็นหลัก
- โปรเจกต์ของคุณมีขนาดเล็กถึงปานกลาง
- คุณต้องการเครื่องมือที่ง่ายกว่าและมี learning curve ที่ต่ำกว่า
- คุณคุ้นเคยกับ npm และ Yarn อยู่แล้ว
เลือก Nx หาก:
- คุณต้องการเวลา build ที่ปรับให้เหมาะสมและ incremental builds
- คุณต้องการความสามารถด้าน code generation
- คุณต้องการระบบ build ที่ครอบคลุมพร้อม task orchestration
- โปรเจกต์ของคุณมีขนาดใหญ่และซับซ้อน
- คุณพร้อมที่จะลงทุนเวลาในการเรียนรู้เครื่องมือที่ทรงพลังกว่า
สามารถใช้ Lerna กับ Nx ได้หรือไม่?
ได้ คุณสามารถใช้ Lerna และ Nx ร่วมกันได้ การผสมผสานนี้ช่วยให้คุณใช้ประโยชน์จากความสามารถในการจัดการแพ็กเกจของ Lerna พร้อมทั้งได้รับประโยชน์จากระบบ build ที่ปรับให้เหมาะสมและ task orchestration ของ Nx Nx สามารถกำหนดค่าให้เป็น task runner สำหรับ Lerna โดยให้ incremental builds และ computation caching สำหรับแพ็กเกจที่จัดการโดย Lerna
แนวทางปฏิบัติที่ดีที่สุดสำหรับการจัดการ Frontend Monorepo
ไม่ว่าคุณจะเลือก Lerna หรือ Nx การปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุดเป็นสิ่งสำคัญอย่างยิ่งในการจัดการ frontend monorepo ให้ประสบความสำเร็จ:
- สร้างโครงสร้างโปรเจกต์ที่ชัดเจน: จัดระเบียบโปรเจกต์ของคุณอย่างมีเหตุผลและสอดคล้องกัน ใช้รูปแบบการตั้งชื่อที่ชัดเจนสำหรับแพ็กเกจและไลบรารี
- บังคับใช้มาตรฐานการเขียนโค้ดที่สอดคล้องกัน: ใช้ linters และ formatters เพื่อให้แน่ใจว่ารูปแบบโค้ดมีความสอดคล้องกันในทุกโปรเจกต์ เครื่องมือเช่น ESLint และ Prettier สามารถรวมเข้ากับเวิร์กโฟลว์ของคุณได้
- ทำให้กระบวนการ Build และ Test เป็นอัตโนมัติ: ใช้ CI/CD pipelines เพื่อทำให้กระบวนการ build, test และ deployment เป็นอัตโนมัติ เครื่องมือเช่น Jenkins, CircleCI และ GitHub Actions สามารถนำมาใช้ได้
- นำ Code Reviews มาใช้: ดำเนินการ code reviews อย่างละเอียดเพื่อให้แน่ใจในคุณภาพโค้ดและความสามารถในการบำรุงรักษา ใช้ pull requests และเครื่องมือ code review
- ติดตามเวลา Build และประสิทธิภาพ: ติดตามเวลา build และ metric ประสิทธิภาพเพื่อระบุคอขวดและส่วนที่ต้องปรับปรุง Nx มีเครื่องมือสำหรับการวิเคราะห์ประสิทธิภาพ build
- จัดทำเอกสารโครงสร้างและกระบวนการ Monorepo ของคุณ: สร้างเอกสารที่ชัดเจนซึ่งอธิบายโครงสร้าง monorepo ของคุณ เครื่องมือและเทคโนโลยีที่ใช้ และเวิร์กโฟลว์การพัฒนา
- นำ Conventional Commits มาใช้: ใช้ conventional commits เพื่อทำให้กระบวนการ versioning และ release เป็นอัตโนมัติ Lerna รองรับ conventional commits ได้ทันที
สรุป
Frontend monorepos นำเสนอข้อได้เปรียบที่สำคัญสำหรับการจัดการโปรเจกต์ขนาดใหญ่และซับซ้อน รวมถึงการแชร์โค้ด, การจัดการ dependencies ที่ง่ายขึ้น และการทำงานร่วมกันที่ดีขึ้น Lerna และ Nx เป็นเครื่องมือที่ทรงพลังที่สามารถช่วยคุณจัดการ frontend monorepo ได้อย่างมีประสิทธิภาพ Lerna เป็นตัวเลือกที่ยอดเยี่ยมสำหรับการจัดการ npm packages ในขณะที่ Nx นำเสนอระบบ build ที่ครอบคลุมมากขึ้นพร้อมคุณสมบัติขั้นสูงเช่น incremental builds และ code generation ด้วยการพิจารณาความต้องการของโปรเจกต์ของคุณอย่างรอบคอบและปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุด คุณสามารถนำ frontend monorepo มาใช้อย่างประสบความสำเร็จและได้รับประโยชน์จากมัน
อย่าลืมพิจารณาปัจจัยต่างๆ เช่น ประสบการณ์ของทีม ความซับซ้อนของโปรเจกต์ และข้อกำหนดด้านประสิทธิภาพ เมื่อเลือกระหว่าง Lerna และ Nx ทดลองใช้ทั้งสองเครื่องมือและค้นหาเครื่องมือที่เหมาะสมกับความต้องการเฉพาะของคุณมากที่สุด
ขอให้โชคดีกับการเดินทางใน monorepo ของคุณ!